﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Net;
using Swoosh.Contracts.MediaPlayerLib;
using Swoosh.Utilities.TraceLogger;
using System.Threading;

namespace Swoosh.MediaPlayers.XbmcEden
{
    public class Player : IPlaybackDevice
    {

        private string _Name;
        public string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        private string _StorageName;
        public string StorageName
        {
            get { return _StorageName; }
            set { _StorageName = value; }
        }

        public Storage Storage
        {
            get
            {
                return SwooshConfig.CurrentConfig.StorageList.Where(s => s.Name == StorageName).FirstOrDefault();
            }
        }

        private Playlist _Playlist;
        public Playlist Playlist
        {
            get { return _Playlist; }
        }

        private XbmcEdenConfig _Config;

        private Thread _ActiveThread;

        private volatile bool _StopFlag;

        public Player()
        {
            _Name = "";
            _StorageName = "";
            _Playlist = new Playlist();
            _StopFlag = false;
        }

        public bool LoadConfiguration(string Configuration)
        {
            bool ret = false;

            XmlSerializer xmlSer = new XmlSerializer(typeof(XbmcEdenConfig));

            try
            {
                _Config = (XbmcEdenConfig)xmlSer.Deserialize(new StringReader(Configuration));

                ret = true;
            }
            catch (Exception ex)
            {
                Logger.Log(LogLevels.Error, Name + " - unable to load configuration", ex);
                _Config = new XbmcEdenConfig();
            }
            return ret;
        }

        public bool Start()
        {
            _StopFlag = false;
            _ActiveThread = new Thread(new ThreadStart(KeepActive));
            _ActiveThread.Start();
            return true;
        }

        public bool Stop()
        {
            _StopFlag = true;
            return true;
        }

        private void KeepActive()
        {
            int i = 9;
            while (!_StopFlag)
            {
                i++;
                if (i >= 30)
                {
                    try
                    {
                        string postData = "{\"method\":\"JSONRPC.Ping\",\"id\" : 0,\"jsonrpc\" : \"2.0\"}";
                        Logger.Log(LogLevels.Trace, "KeepEdenAlive");
                        string ret = SendCommand(postData);
                        Logger.Log(LogLevels.Trace, "Eden reports Alive.");
                        
                    }
                    catch
                    {
                        Logger.Log(LogLevels.Trace, "Eden reports Dead.");
                    }
                    i = 0;
                }
                Thread.Sleep(1000);                
            }
        }

        private string SendCommand(string postData)
        {
            string requesturi = "http://" + _Config.ServerName + ":" + _Config.ServerPort + "/JSONRPC";

            WebRequest web_request = WebRequest.Create(requesturi);

            UTF8Encoding encoding = new UTF8Encoding();
            
            byte[] data = encoding.GetBytes(postData);

            // Prepare web request...
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requesturi);
            request.Method = "POST";
            request.ContentType = "application/json";
            request.ContentLength = data.Length;
            Stream newStream = request.GetRequestStream();
            // Send the data.
            newStream.Write(data, 0, data.Length);
            newStream.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream res = response.GetResponseStream();
            StreamReader reader = new StreamReader(res);
            string ret = reader.ReadToEnd();

            return ret;
        }

        private int InitializePlaylist()
        {
            // assume videoplaylist is always id 1;
            int id = 1;

            // search for videoplaylist id

            //string postData = "{\"method\":\"Playlist.GetPlaylists\",\"id\" : 0,\"jsonrpc\" : \"2.0\"}";
            //Logger.Log(LogLevels.Debug, postData);
            //string playlists = SendCommand(postData);
            //Logger.Log(LogLevels.Debug, playlists);
            //bool success = false;
            //Hashtable ht = (Hashtable)JSON.JsonDecode(playlists, ref success);

            //ArrayList res = (ArrayList)ht["result"];

            //if (res.Cast<Hashtable>().Where(r => r["type"].ToString() == "video").Any())
            //{
            //    id = res.Cast<Hashtable>().Where(r => r["type"].ToString() == "video").Select(r => Convert.ToInt32(r["playlistid"])).FirstOrDefault();
            //}
            //else
            //{
            //    throw new Exception("Video Playlist not found.");
            //}

            return id;

        }

        private int InitializePlayer()
        {
            // assume videoplayer is always id 1;
            int id = 1;

            // search for videoplaylist id

            //string postData = "{\"method\":\"Player.GetActivePlayers\",\"id\" : 0,\"jsonrpc\" : \"2.0\"}";
            //Logger.Log(LogLevels.Debug, postData);
            //string player = SendCommand(postData);
            //Logger.Log(LogLevels.Debug, player);
            //bool success = false;
            //Hashtable ht = (Hashtable)JSON.JsonDecode(player, ref success);

            //ArrayList res = (ArrayList)ht["result"];

            //if (res.Cast<Hashtable>().Where(r => r["type"].ToString() == "video").Any())
            //{
            //    id = res.Cast<Hashtable>().Where(r => r["type"].ToString() == "video").Select(r => Convert.ToInt32(r["playerid"])).FirstOrDefault();
            //}
            //else
            //{
            //    throw new Exception("Video Player not found.");
            //}

            return id;

        }

        public bool ClearPlaylist()
        {
            int pid = InitializePlaylist();
            string postData = "{\"method\":\"Playlist.Clear\",\"params\":{\"playlistid\":" + pid + "},\"id\":0,\"jsonrpc\":\"2.0\"}";
            Logger.Log(LogLevels.Debug, postData);
            string res = SendCommand(postData);
            Logger.Log(LogLevels.Trace, res);
            return true;
        }

        public bool QueuePlaylistItem(PlaylistItem Item)
        {
            int pid = InitializePlaylist();
            string postData = "{\"method\":\"Playlist.Add\",\"params\":{\"playlistid\":" + pid + ",\"item\":{\"file\":\"" + Item.File.Replace("\\", "//").Replace("//", "\\\\") + "\"}}, \"id\" : 0,\"jsonrpc\" : \"2.0\"}";
            Logger.Log(LogLevels.Debug, postData);
            string res = SendCommand(postData);
            Logger.Log(LogLevels.Debug, res);
            return true;
        }

        public bool StopPlayback()
        {
            int pid = InitializePlayer();
            string postData = "{\"method\":\"Player.Stop\",\"params\":{\"playerid\":" + pid + "},\"id\":0,\"jsonrpc\":\"2.0\"}";
            Logger.Log(LogLevels.Debug, postData);
            string res = SendCommand(postData);
            Logger.Log(LogLevels.Debug, res);
            return true;
        }

        public bool PlayPlaylistItem(PlaylistItem Item)
        {
            int pid = InitializePlaylist();

            string postData = "{\"method\":\"Player.Open\",\"params\":{\"item\":{\"position\":" + Item.Position + ",\"playlistid\":" + pid + "}},\"id\":0,\"jsonrpc\":\"2.0\"}";
            Logger.Log(LogLevels.Debug, postData);
            string res = SendCommand(postData);
            Logger.Log(LogLevels.Debug, res);
            
            SeekInCurrentPlayback(Item);
            
            return true;
        }

        private bool SeekInCurrentPlayback(PlaylistItem Item)
        {
            int pid = InitializePlayer();
            string postData = "{\"method\":\"Player.Seek\",\"params\":{\"playerid\":" + pid + ",\"value\":{\"hours\":" + (Item.SeekTime / 3600) + ",\"minutes\":" + (Item.SeekTime / 60) % 60 + ",\"seconds\":" + (Item.SeekTime) % 60 + ",\"milliseconds\":" + (0) + "}},\"id\":0,\"jsonrpc\":\"2.0\"}";
            Logger.Log(LogLevels.Debug, postData);
            string res = SendCommand(postData);
            Logger.Log(LogLevels.Debug, res);
            return true;
        }

        public Playlist ReadPlayList()
        {
            _Playlist = new Playlist();

            //int playlistid = InitializePlaylist();
            //int playerid = InitializePlayer();

            //string postData = "{\"method\":\"Playlist.GetItems\",\"params\":{\"playlistid\":" + playlistid + ",\"properties\":[\"title\",\"file\"]},\"id\":0,\"jsonrpc\":\"2.0\"}";
            //string retData = SendCommand(postData);

            //JObject jobj = JObject.Parse(retData);

            //Logger.Log(LogLevels.Debug, "paused: " + jobj["result"]["paused"].Value<bool>().ToString());

            return _Playlist;
        }



    }
}
